/*
SchemaAppController
Version 1.0
Description: Controller class for VF Page:SchemaApp.This class extracts whole schema for an ORG.
Auhtor: Pratibh Prakash
Created Date: 28 Apr-2009
LastModified Date: 	9 June-2009, Change in code logic removed message for Filter commandLinks 
					as search button is removed as all search will be performed by commandLinks only.
*/
public class SchemaAppController {
    /*
    Class for Storing Descrption of Fields in an Object.
    */
    public class FieldDescription{
        public String Name {get; set;}  
        public String Label {get; set;}  
        public String References {get; set;}
        public String FieldType {get; set;} 
        public Boolean Custom {get; set;}  
       
    }
    
    List<String> SObjectList = new List<String>(); 
    List<FieldDescription> SObjectFieldList = new List<FieldDescription>(); 
    List<FieldDescription> SObjectFieldList_forLabel = new List<FieldDescription>(); 
    List<String> Relations = new List<String>();
    public Boolean Flag {get; set;}//Used in generating message.  
    public String Message {get; set;}
    Set<String> Fake_Org = new Set<String>();// List for avoid duplicate object names as returned by Schema Describe.
    Set<String> Fake = new Set<String>();// List for avoid duplicate object names as returned by Schema Describe.
    String selectedObj ='';
    public String SearchObj {get; set;}
    public String SearchText {get; set;}
    Map<String, Schema.SObjectType> schemaMap = new Map<String, Schema.SObjectType>();
    Schema.ChildRelationship[] childObjects;
    
    /*
    Getter for generating commandlink list:(A-Z)
    */
    public List<String> getCommandLinks(){
    	List<String> CommandLinks = new List<String>();
    	CommandLinks.clear();//List cleared to avoid Governor limit exception as method is called on Tab switching.
    	CommandLinks.add('A');CommandLinks.add('B');CommandLinks.add('C');CommandLinks.add('D');
    	CommandLinks.add('E');CommandLinks.add('F');CommandLinks.add('G');CommandLinks.add('H');
    	CommandLinks.add('I');CommandLinks.add('J');CommandLinks.add('K');CommandLinks.add('L');
    	CommandLinks.add('M');CommandLinks.add('N');CommandLinks.add('O');
    	CommandLinks.add('P');CommandLinks.add('Q');CommandLinks.add('R');
    	CommandLinks.add('S');CommandLinks.add('T');CommandLinks.add('U');
    	CommandLinks.add('V');CommandLinks.add('W');CommandLinks.add('X');
    	CommandLinks.add('Y');CommandLinks.add('Z');CommandLinks.add('ALL');
    	return CommandLinks;
    	
    }
    /*
    Method Filters Object list according to selected starting character.
    */
    public void filterSObjectList(){
    	SObjectList.clear();//List cleared to avoid Governor limit exception as method is called on Tab switching.
    	Relations.clear();//List cleared to avoid Governor limit exception as method is called on Tab switching.
    	SelectedObj ='';
    	String startingChar = System.currentPageReference().getParameters().get('links');
    	if(startingChar!=null){
    		Fake.clear();
	    	schemaMap = Schema.getGlobalDescribe();
	        Schema.SObjectType[] obj = schemaMap.values();
	        for(integer i=0; i<obj.size(); i++){
	        	Schema.DescribeSObjectResult R = obj[i].getDescribe();
		        String str = R.getName();//
		        if((str.startsWith(startingChar) || startingChar.equals('ALL'))){
			    	if(!Fake.contains(str)){
			        	SObjectList.add(str);
			            Fake.add(str);
			        }
		        }
	    	}
    	}
    }
    /*
    Method retrieves list of all SObjects in an ORG.
    */    
    public List<String> getSObjectList(){
        //SObjectList.clear();
        String startingChar = System.currentPageReference().getParameters().get('links');
        if(startingChar==null){
        	schemaMap = Schema.getGlobalDescribe();
	        Schema.SObjectType[] obj = schemaMap.values();
	        for(Integer i=0; i<obj.size(); i++){
		        Schema.DescribeSObjectResult R = obj[i].getDescribe();
			    String str = R.getName();
			    if(!Fake_org.contains(str)){
			    	SObjectList.add(str);
			        Fake_org.add(str);
			    }
	        }
	    }
	    SObjectList.sort();
	    return SObjectList;
    }
    /*
    Method retrieves list of all Child Objects for a selected SObject.
    */    
    public void findRelationships(){
        Fake.clear();//List cleared to avoid Governor limit exception as method is called on Tab switching.
        Relations.clear();//List cleared to avoid Governor limit exception as method is called on Tab switching.
        SelectedObj = System.currentPageReference().getParameters().get('sobj');
        Schema.DescribeSObjectResult descRes;
        descRes = schemaMap.get(SelectedObj).getDescribe();
        if(descRes!= null){
            List<Schema.ChildRelationship> childObjects  = descRes.getChildRelationships();
            for(Integer i=0; i< childObjects.size(); i++){
                String str = (childObjects[i].getChildSObject().getDescribe()).getName();
                if(str!=SelectedObj && !(Fake.contains(str))){
                    Relations.add(str);
                    Fake.add(str);
                }
            }
            if(Relations.size()<1 && SelectedObj.length() >0){
                ApexPages.Message myMsg = new ApexPages.Message(ApexPages.Severity.INFO, 'No Child Relationships found');
                ApexPages.addMessage(myMsg);
            }
        }
    }
    /*
    Getter for VF Page: PageBlockTable for child objects.
    */
    public List<String> getRelations(){
        return Relations;
    }
    /*
    Getter for retreiving Name of Object selected on VF Page.
    */
    public String getSelectedObj(){
        if(SelectedObj.length()<1){
            ApexPages.Message myMsg = new ApexPages.Message(ApexPages.Severity.INFO, 'Please Select a Object');
            ApexPages.addMessage(myMsg);
            return('');
        }
        else{
            return (':    '+SelectedObj);
        }
    }
    /*
    Getter for generating SObject picklist on VF Page.
    */
    public List<SelectOption> getObjects() {
        Fake.clear();//List cleared to avoid Governor limit exception as method is called on Tab switching.
        List<String> SObjectList_For_FieldSearchTab = new List<String>();
        SObjectList_For_FieldSearchTab.clear();
        Schema.SObjectType[] obj = schemaMap.values();
        List<SelectOption> options = new List<SelectOption>();
        options.clear();
        options.add(new SelectOption('SCR','--SELECT OBJECT --'));
        for(Integer i=0; i<obj.size(); i++){
        	Schema.DescribeSObjectResult R = obj[i].getDescribe();
			String str = R.getName();
			if(!Fake.contains(str)){
				SObjectList_For_FieldSearchTab.add(str);
		       	Fake.add(str);
			}
        }
        obj.clear();
        SObjectList_For_FieldSearchTab.sort();
        for(Integer i=0; i<SObjectList_For_FieldSearchTab.size();i++){
        	options.add(new SelectOption(SObjectList_For_FieldSearchTab[i],SObjectList_For_FieldSearchTab[i]));
        }
        return options;
    }
    /*
    Method searches field in the selected Object.
    */
    public void searchField(){
    	String fieldFilter = System.currentPageReference().getParameters().get('fieldFilter');//Paramter serach to be perofrmed on CUSTOM, STANDARD or both type of fields. 
    	//List cleared to avoid Governor limit exception as method is called on Tab switching.
        Schema.DescribeSObjectResult descRes;
        if(SearchText.length()<1){
        	Message = 'Please Enter Search value.';
        	Flag=true;
        }
        else if(SearchObj.equals('SCR')){
        	Message = 'Please Select a Object.';
        	Flag=true;
        }
        else{
        	SObjectFieldList.clear();
        	descRes = schemaMap.get(SearchObj).getDescribe();
		    Map<String, Schema.SObjectField> currObjFields = descRes.fields.getMap();
		    Schema.SObjectField[] arrayFields = currObjFields.values();
		    for(Integer i=0; i<arrayFields.size(); i++){
		    	Flag= false;
		        Schema.DescribeFieldResult fieldDesc = arrayFields[i].getDescribe();
		        //String str = fieldDesc.getLabel();
		        FieldDescription obj = new FieldDescription();
		        //Searching fields according to text enterd by User.
		        if((fieldDesc.getLabel().toLowerCase()).contains(SearchText.toLowerCase()) || (fieldDesc.getName().toLowerCase()).contains(SearchText.toLowerCase())||(SearchText.equals('*'))){
		        	obj.Name = fieldDesc.getName();
		            obj.Label = fieldDesc.getLabel();
		            obj.FieldType = (fieldDesc.getType()).name();
		            if((obj.FieldType).equals('REFERENCE')){
		            	obj.References='';
		            	
		            	List <SObjectType> referenceList = fieldDesc.getReferenceTo();
		            	for(Integer j=0; j<referenceList.size(); j++){
		            		if(j!=0){
		            			obj.References +=', ';
		            		}
		            		Schema.DescribeSObjectResult R = referenceList[j].getDescribe();
			    			String str = R.getName();
			    			obj.References += str;
		            	}
		            	
		            }
		            //obj.FieldType = fieldDesc.getRelationshipName();
		            obj.Custom = fieldDesc.isCustom();
		            //Adding searched field based on User Preferences i.e CUSTOM, STANDARD or both.
		            if(fieldFilter!=null){
			            if(fieldFilter.equals('All')){
			            	SObjectFieldList.add(obj);
			            }
			            else if(fieldFilter.equals('CUS')){
			            	if(fieldDesc.isCustom()){
			            		SObjectFieldList.add(obj);
			            	}
			            }
			            else if(fieldFilter.equals('STD')){
			            	if(!fieldDesc.isCustom()){
			            		SObjectFieldList.add(obj);
			            	}
			            }
		            }
		            else{
		            	SObjectFieldList.add(obj);
		            }
		        }
		     }
		     
		     if(SObjectFieldList.size()<1){
		     	Message = 'No results found.';
		        Flag=true;
		     }
       	}
    }
    /*
    Getter for VF Page: PageBlockTable for list of searched fields.
    */
    public List<FieldDescription> getSObjectFieldList(){
        return SObjectFieldList;
    }
}